#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;




void removeConsoleBuffer(){
	HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(console, &mode);
	SetConsoleMode(console, mode & ~ENABLE_LINE_INPUT);
	cin >> noskipws;
};

void initialiseRandomNumberGenerator(){
	srand((int)time(0));
};

enum {AC, fortitude, reflex, will};

struct attackData{
	
	const char *name;
	const char *key; // key if under player control
	int ammo;  // how many attacks if limited, or -1 if unlimited
	int targetDefence;
	int bonus;
	int damageBonus;
	int damageDice;
};

attackData playerAttacks[] = {

	//name       key ammo defence mod dmg dice
	{"shoot",	 "s",  6, reflex,  5,  10,  10 },
	{"punch",	 "p", -1, AC,     15,   3,   4 },
	{"kick",	 "k", -1, AC,     14,   4,   4 },
	{"headbutt", "h", -1, reflex,  8,   8,  10 },
};

attackData dragonAttacks[] = {

	//name       key ammo defence mod dmg dice
	{"burn",     "b",  1, reflex,  8,  10, 10 },
	{"claw",     "c", -1, AC,      8,   5, 10 },
};

struct character{

	int initiative;
	int hitPoints;
	int defences[4];
	attackData *attacks;
	int numberOfAttacks;
	bool playerControl;
	const char *name;
};

int roll(int sides){
	
	return rand() % sides + 1;
};

int rollInitiative (character *combatant){
	
	return roll(20) + combatant->initiative;
};

char getKeypress(){
	char answer;
	cin >> answer; // wait for keypress to end
	return answer;
};

void printAttackOption (attackData *attack, const char *defender){
	cout << "[" << attack->key << "] ";
	cout << attack->name << " the " << defender << "," << endl;
};

void listAttackOptions (character *attacker, const char *defender){
	for (int i = 0; i < attacker->numberOfAttacks; ++i){
		printAttackOption(&attacker->attacks[i], defender);
	}
};

void doAttack (attackData *attack, character *defender){
	if (roll(20) + attack->bonus > defender->defences[attack->targetDefence]) {
		int damage = roll(attack->damageDice) + attack->damageBonus;
		defender->hitPoints -= damage;
		cout << "a hit for " << damage << " points of damage." << endl;
	}else{
		cout <<"miss." << endl;
	}
	if (attack->ammo > 0) {
		attack->ammo--;
	}
}

void announce (const char *enemyType){
	cout <<"A " << enemyType << " appears!" << endl;
	cout << endl;
}

void announceTurn (const char *name){
	cout << "It's the " << name << "'s turn." << endl;
}

char getAttackKey (attackData *attack){
	return attack->key[0];
}

bool attackNeedsAmmo (attackData *attack){
	return attack->ammo != -1;
}

bool attackHasAmmo (attackData *attack){
	return attack->ammo > 0;
}

bool canUseAttack (attackData *attack){
	return !attackNeedsAmmo || attackHasAmmo;
}

int  choosePlayerAttack (character *attacker, character *defender){
	int choice = -1;
	char answer;

	do {
		cout << "Will you:" << endl;
		listAttackOptions(attacker, defender->name);
		cout << "[r] run away." << endl;
		cout << endl;
		cout << ">";

		answer = getKeypress();

		for (int i = 0; i < attacker->numberOfAttacks; ++i){
			if (answer == getAttackKey(&attacker->attacks[i])){
				if (canUseAttack(&attacker->attacks[i])){
					cout << endl;
					cout << endl;
					cout << "You attempt to " << attacker ->attacks[i].name <<" the " << defender->name << "..." << endl;
					choice = i;
				} else {
					cout << endl;
					cout << endl;
					cout << "You are out of ammo!" << endl;
					answer = '?';
				}
			}
		}
		if (choice == -1) {
			switch (answer) {

			case 'r':
				cout << endl;
				cout << endl;
				break;

			default:
				cout << endl;
				cout << endl;
				cout << "I didn't understand that." << endl;
				cout << endl;
				answer = '?';
				break;
			}
		}
	}while (answer == '?');
	return choice;
}

int chooseAIAttack (character *attacker, character *defender){
	int choice;
	do {
		choice = rand() % attacker->numberOfAttacks;
		if(canUseAttack(&attacker->attacks[choice])) {
			cout << "The " << attacker->name << " tries to ";
			cout << attacker->attacks[choice].name << " the ";
			cout << defender->name << "..." << endl;
		} else {
			choice = -1;
		}
	} while (choice == -1);
	return choice;
}

void initialisePlayer (character *player){
	player->initiative = 4;
	player->hitPoints = 20;
	player->defences[AC] = 20;
	player->defences[fortitude] = 12;
	player->defences[reflex] = 18;
	player->defences[will] = 15;
	player->attacks = playerAttacks;
	player->numberOfAttacks = sizeof(playerAttacks) / sizeof(playerAttacks[0]);
	player->playerControl = true;
	player->name = "hero";
}

void initialiseDragon(character * dragon)
{
	dragon->hitPoints = 20;
	dragon->initiative = 8;
	dragon->defences[AC] = 20;
	dragon->defences[fortitude] = 20;
	dragon->defences[reflex] = 12;
	dragon->defences[will] = 15;
	dragon->attacks = dragonAttacks;
	dragon->numberOfAttacks = 2;
	dragon->playerControl = false;
	dragon->name = "dragon";
}

bool processCombatTurn (character *attacker,  character *defender){
	bool flee = false;
	
	int chosenAttack = -1; // no chosenAttack (flee instead)
	announceTurn(attacker->name);
	
	if (attacker->playerControl) {
		
		chosenAttack = choosePlayerAttack(attacker, defender);
	
	} else { // enemy's turn
		
		chosenAttack = chooseAIAttack(attacker, defender);
	
	} if (chosenAttack != -1) {
		
		doAttack(&(attacker->attacks[chosenAttack]), defender);
	
	} else {
		
		flee = true;
	
	} return flee;
}









int main()
{
	removeConsoleBuffer();
	initialiseRandomNumberGenerator();

	character player;
	character dragon;

	initialisePlayer(&player);
	initialiseDragon(&dragon);

	character *enemy = &dragon;
	announce (enemy->name);

	character *attacker = enemy;
	character *defender = &player;

	if (rollInitiative(&player) > rollInitiative(enemy)) {
		swap(attacker, defender);
	}

	bool flee = false;
	do {
		
		flee = processCombatTurn (attacker, defender);
		swap(attacker, defender);
	
	} while (attacker->hitPoints > 0 && defender->hitPoints > 0 && !flee);
	
	if (player.hitPoints < 1){
		
		cout << "You died!" << endl;

	}else if (enemy -> hitPoints < 1) {

		cout << "You defeated the " << enemy->name << "!" << endl;
	
	} else {
	
		cout << "You live to fight another day..." << endl;
	
	}
	getKeypress ();
	return 0;
}




void oldCode (){
	//// Defenses


	//struct character {

	//	

	//	bool isPlayer;

	//	int defences[4];

	//	// Attacks
	//	char *rangeWeaponName;
	//	
	//	char *rangeAttackName;           // Player = Pistol | Dragon = FireBreath
	//	
	//	char *ammoName;
	//	int rangeAttackBonus;
	//	int rangeDamageBonus;
	//	int rangeDamageDice;

	//	// char *meleWeaponName; --?
	//	char *meleAttackName;            // Player = Punch | Dragon = Claw
	//	int meleAttackBonus;
	//	int meleDamageBonus;
	//	int meleDamageDice;
	//	
	//	// bool dirtInFace;
	//	// bool dirtInFaceUsed;
	//	// int dirtBonus;   // = (dirtInFace)? 2 : 1;

	//	// const char *dirtBonusAttackName;

	//};

	//char answer;
	//
	//				// {CharName, isPlr, {AC, HP, Re, Init}, rWName,       rWCmd  rWAttack       amm, ammoName,  AB, DB, DD, mNam, AB, DB, DD, Dirt, DirtUsed, DirtBonus, DirtBonusNam}; 

	//character Player = {"Hero",   true,  {20, 20, 15, 4},"pistol",         "[s]", "shoot",         4,"bullet(s)", 5, 10, 10, "Punch", 15, 3, 3 ,/* false, false,  DirtBonus, "Roundhouse Kick" */};
	//character Dragon = {"Dragon", true,  {20, 20, 16, 8},"Breath of Death","[b]", "breathe fire",  2,"Breath(s)", 8, 10, 10, "Claw",  8 , 5, 10,/* false, false,  DirtBonus, "Bite"            */};  

	//bool do_combat = true;
	//bool player_turn = (rand() % 20 + 1 + Player.defences[initiative] > rand() % 20 + 1 + Dragon.defences[initiative]);




	//cout << "Enter the name of our Knight of the Realm:" << endl;
	//cin >> Player.characterName ;


//	cout << "A " << defender->characterName << "!" << endl;
//	cout << endl;
//
//	do {
//
//		if (attacker->isPlayer) {
//
//			// dirtInDragonsFaceUsed = false;
//
//			do {
//				cout << endl;
//				cout << attacker ->characterName << ", will you:" << endl;
//				cout << attacker->rangeCmd <<" "<< attack->name <<" at the " << defender->characterName << ", or" << endl;
//				//cout << "[p] punch the " << defender->characterName << "," << endl;
///*				if (!dirtInDragonsFace){ cout << "[d] fight dirty," << endl;}
//				if (dirtInDragonsFace){ cout << "[t] wind up for a power attack" << endl; }            */
//				cout << "[r] run away?" << endl;
//				cout << endl;
//				cout << ">";
//
//				cin >> answer;
//
//				switch (answer) {
//
//				case 'b': 
//				case 's': 
//					if (attacker->rangeAmmo > 0) {
//						cout << endl;
//						cout << endl;
//						cout << "You " << attacker->rangeAttackName << " at the " << defender->characterName << " with your " << attacker->rangeWeaponName << "..." << endl;
//						/* if (rand() % 20 + 1 + Player.rangeAttackBonus >= Dragon.defences[AC]) {
//							cout << "Your bullet pierces the dragon." << endl;
//							Dragon.defences[hitPoints] -= rand() % Player.rangeDamageDice + 1 + Player.rangeDamageBonus;} 
//							else {cout << "Your shot bounces off the dragon's tough scales." << endl;}
//							Player.rangeAmmo--; */
//
//					} else {
//						cout << endl;
//						cout << endl;
//						cout << "You are out of " << attacker->ammoName << "!" << endl;
//						answer = '?'; 
//					}
//					break;
//
//				/* case 'p':
//					cout << "You attempt to punch the dragon in the face..." << endl;
//					if (rand() % 20 + 1 + Player.meleAttackBonus >= Dragon.defences[AC]) {
//
//						cout << "your punch connects." << endl;
//
//						Dragon.defences[hitPoints] -= rand() % Player.meleDamageDice + 1 + Player.meleDamageBonus, dirtBonus;
//
//					} else {
//
//						cout << "your swing misses." << endl;
//					}
//					break;  */
//
//				//case 't':
//				//	cout << "You attempt a turn into a full roundhouse to the head" << endl;
//				//	if (rand() % 20 + 1 + Player.meleAttackBonus >= Dragon.defences[AC]) {
//
//				//		cout << "the kick connects." << endl;
//
//				//		Dragon.defences[hitPoints] -= rand() % Player.meleDamageDice + 1 + Player.meleDamageBonus /* dirtBonus */;
//
//				//	} else {
//
//				//		cout << "your kick misses." << endl;
//				//	}
//				//	break;
//
//				//	/////// 0000000001111111111222222222233333333334444444444555555555566666666667777777777
//				//case 'd':
//				//	cout << endl;
//				//	cout << "the dragon rears but you telegraph his move," << endl;
//				//	cout << "seeing the opportunity open you react quickly," << endl;
//				//	cout << "kicking up dirt  at his face..." << endl;
//
//				//	if (rand() % 20 + 1 + player_initiative >= dragon_reflex)
//				//	{
//				//		dirtInDragonsFace = true;
//				//		dirtInDragonsFaceUsed = true;
//				//		cout << "the dirt goes in the dragon's eyes and in the seconds advantage that you gain" << endl;
//				//	}
//				//	else 
//				//	{
//				//		cout << "the dirt flies over his shoulder and you have squandered a chance at your enemy" << endl;
//				//	}
//
//				//	break;
//
//
//				case 'r':
//					cout << endl;
//					cout << "The " << defender->characterName << " attacks as you flee..." << endl;
//
//					/*if (rand() % 20 + 1 + Dragon.meleAttackBonus + 2 >= Player.defences[AC] - 5) {
//
//						cout << "the claws penetrate your armour and bite into your flesh." << endl;
//						Player.defences[hitPoints] -= rand() % Dragon.meleDamageDice + 1 + Dragon.meleDamageBonus;
//
//					} else {
//
//						cout << "the claws scratch your armour but you are unharmed." << endl;
//					}
//					cout << endl;*/
//					flee = true;
//
//					break;
//
//				default:
//					cout << endl;
//					cout << endl;
//					cout << "I didn't understand that." << endl;
//					cout << endl;
//					answer = '?';
//					break;
//				}
//
//				/*if (!dirtInDragonsFaceUsed)
//				{
//					dirtInDragonsFace = false;
//				}
//*/
//			} while (answer == '?');
//
//		} else { // switch attacker turn
//
//			if (flee) {
//				opportunityAttack = true;
//			}else {
//				cout << "The "<< attacker->characterName << " attacks you..." << endl;
//			}
//		}
//
//		if (opportunityAttack || !flee) {
//
//			int attack_bonus = attacker->rangeAttackBonus + (opportunityAttack? 2 : 0);
//			int defence = defender->defences[AC] - (opportunityAttack? 5 : 0);
//			if (rand() % 20 + 1 + attack_bonus >= defence) {
//
//				int damage = rand() % attacker->rangeDamageDice + 1 + attacker->rangeDamageBonus;
//				cout << "a hit for " << damage << " points of damage!" << endl;
//				defender->defences[hitPoints] -= damage;
//				attacker->rangeAmmo --;
//				cout << "you have " << attacker->rangeAmmo <<" "<< attacker->ammoName <<" left" << endl;
//
//
//			} else {
//
//				cout << "miss!" << endl;
//				attacker->rangeAmmo --;
//				cout << "you have " << attacker->rangeAmmo <<" "<< attacker->ammoName <<" left" << endl;
//			}
//		}
//		
//		//(!dirtInDragonsFace){
//		//		if (!used_fire_breath && rand() % 2 == 0) {
//
//		//			cout << "The dragon breathes fire at you..." << endl;
//
//		//			if (rand() % 20 + 1 + dragon_breath_attack_bonus >= player_reflex) {
//
//		//				cout << "and you are burned." << endl;
//		//				player_hit_points -= rand() % dragon_breath_damage_dice + 1 + dragon_breath_damage_bonus;
//
//		//			} else {
//
//		//				cout << "but you manage to dodge the blast." << endl;
//		//			}
//		//			used_fire_breath = true;
//
//		//		} else {
//
//		//			cout << "The dragon takes a swipe at you with its massive claws..." << endl;
//
//		//			if (rand() % 20 + 1 + dragon_claw_attack_bonus >= player_AC) {
//
//		//				cout << "the claws penetrate your armour and bite into your flesh." << endl;
//		//				player_hit_points -= rand() % dragon_claw_damage_dice + 1 + dragon_claw_damage_bonus;
//
//		//			} else {
//
//		//				cout << "the claws scratch your armour but you are unharmed." << endl;
//		//			}
//		//		}
//		//	}
//		//}
//
//		  character * temporary = attacker;
//          attacker = defender;
//          defender = temporary;
//
//	} while (attacker->defences[hitPoints] > 0 && defender->defences[hitPoints] > 0 && !opportunityAttack || flee);
//
//	if (Player.defences[hitPoints] < 1) {
//
//		cout << "The " << Player.characterName << " died!" << endl;
//
//	} else if (Dragon.defences[hitPoints] < 1) {
//
//		cout << "The " << Player.characterName << " defeated the dragon!" << endl;
//
//	} else {
//
//		cout << "The " << defender->characterName << " lives to fight another day..." << endl;
//	}
//
//	cin >> answer; // wait for keypress to end
//
//	return 0;
//}
};
